package org.libermundi.theorcs.core.model;

import java.io.Serializable;
import java.util.List;

import org.libermundi.theorcs.core.exceptions.NodeNotFoundException;
import org.libermundi.theorcs.core.model.NodeConstrain.Mode;

public interface Node<T extends NodeData> extends Serializable, Cloneable {
	/**
	 * Returns the Id of the {@link Node}
	 */
	String getId();
	
	/**
	 * Setter for the Id of the Node
	 * @param id
	 */
	void setId(String id);
	
	/**
	 * Returns the Id of the Parent of this {@link Node}
	 * @return the Id or null
	 */
	String getParentId();
	
	/**
	 * Setter for the Id of the Node
	 * @param id
	 */
	void setParentId(String parentId);
	
	/**
	 * Return the children of {@link Node}. The {@link Tree} is represented by a single
	 * root {@link Node} whose children are represented by a List<Node<T>>. Each of
	 * these {@link Node} elements in the List can have children. The getChildren()
	 * method will return the children of a {@link Node}.
	 * @return the children of {@link Node}
	 */
	List<Node<T>> getChildren();

	/**
	 * Sets the children of a Node<T> object. See docs for getChildren() for
	 * more information.
	 * @param children the List<Node<T>> to set.
	 */
	void setChildren(List<Node<T>> children);
	
	/**
	 * Returns the number of immediate children of this Node<T>.
	 * @return the number of immediate children.
	 */
	int getNumberOfChildren();
	
	/**
	 * Adds a child to the list of children for this Node<T>. The addition of
	 * the first child will create a new List<Node<T>>.
	 * @param child a Node<T> object to set.
	 */
	void addChild(Node<T> child);
	
	/**
	 * Inserts a Node<T> at the specified position in the child list. Will
	 * throw an ArrayIndexOutOfBoundsException if the index does not exist.
	 * @param index the position to insert at.
	 * @param child the Node<T> object to insert.
	 * @throws IndexOutOfBoundsException if thrown.
	 */
	void insertChildAt(int index, Node<T> child) throws IndexOutOfBoundsException;
	
	/**
	 * Remove the Node<T> element at index index of the List<Node<T>>.
	 * @param index the index of the element to delete.
	 * @throws IndexOutOfBoundsException if thrown.
	 */
	void removeChildAt(int index) throws IndexOutOfBoundsException;
	
	/**
	 * Getter of the Data Object
	 * @return the Data
	 */
	T getData();
	
	/**
	 * Setter of the Data Object
	 * @param data
	 */
	void setData(T data);

	/**
	 * Search for a Node with this specific Id in its Children
	 * @param id
	 * @return corresponding Node
	 * @throws NodeNotFoundException
	 */
	Node<T> getChild(String id);
	
	/**
	 * Returns true of Node have at least 1 Child
	 * @return true or false
	 */
	boolean hasChildren();
	
	boolean hasConstrains();
	
	boolean mustDisplay();
	
	List<NodeConstrain> getConstrains();
	
	void addConstrain(NodeConstrain constrain);
	
	void addAllConstrains(List<NodeConstrain> constrains);
	
	/**
	 * Allow to overide the default behavior {@link NodeConstrain.Mode#ALL}
	 * @param mode
	 */
	void setConstrainMode(Mode mode);
	
	Mode getConstrainMode();
	
	Node<T> clone() throws CloneNotSupportedException;
	
	void setDisplayIfEmpty(boolean displayIfEmpty);
	
	boolean isDisplayIfEmpty();

}
